package com.cube.share.async.executor;

import com.cube.share.base.function.CatchExceptionFunction;
import com.cube.share.base.templates.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.util.concurrent.*;

/**
 * @author cube.li
 * @date 2022/2/19 16:01
 */
@Slf4j
public class AsyncExecutor implements InitializingBean, DisposableBean, BeanNameAware {

    private ThreadPoolExecutor executor;

    @Nullable
    private String beanName;

    public ThreadPoolExecutor getExecutor() {
        return executor;
    }

    public void setExecutor(ThreadPoolExecutor executor) {
        this.executor = executor;
    }

    @Override
    public void afterPropertiesSet() {
        log.info("加载AsyncExecutor...");
    }

    @Override
    public void setBeanName(@NonNull String name) {
        this.beanName = name;
    }

    public <R> Future<R> executeWithResult(Callable<R> callable) {
        return executor.submit(callable);
    }

    public void execute(Runnable runnable) {
        executor.execute(runnable);
    }

    public <R> R acquireResult(Future<R> future) {
        try {
            return future.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            throw new CustomException(e);
        }
    }

    public void executeAndCatchException(CatchExceptionFunction runnable, String logMessage) {
        executor.execute(() -> CatchExceptionFunction.execute(logMessage, runnable));
    }

    @Override
    public void destroy() throws Exception {
        if (this.executor != null) {
            this.executor.shutdown();
            //尝试等待正在执行中的任务完成
            if (!this.executor.awaitTermination(10, TimeUnit.SECONDS)) {
                log.info("Timed out while waiting for executor" +
                        (this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
            }
        }
    }
}
